package org.mv.mm.docs.nodes;

import java.awt.datatransfer.Transferable;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Action;
import org.mv.mm.api.Doc;
import org.mv.mm.api.Fragment;
import org.mv.mm.api.capabilities.IRefreshableFragmentViewCapability;
import org.mv.mm.api.data.IDataProvider;
import org.mv.mm.common.CentralLookup;
import org.mv.mm.docs.FragmentFlavor;
import org.mv.mm.docs.FragmentNewType;
import org.openide.actions.PasteAction;
import org.openide.actions.ReorderAction;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.NodeTransfer;
import org.openide.util.Utilities;
import org.openide.util.datatransfer.NewType;
import org.openide.util.datatransfer.PasteType;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;

/**
 *
 * @author Martin
 */
public final class FragmentRootNode extends AbstractNode {

  private IDataProvider dataProvider;
  private InstanceContent instanceContent;
  private FragmentNewType fragmentType = null;
  private static final Logger logger = Logger.getLogger(FragmentRootNode.class.getName());
  private IRefreshableFragmentViewCapability rvc;
  private final Doc doc;

  /**
   * Constructor which prepares attributes for the parent constructor of
   * AbstractNode.
   *
   * @param dataProvid
   */
  public FragmentRootNode(IDataProvider dataProvid, Doc document) {
    this(dataProvid, document, new InstanceContent());
  }

  /**
   * Private constructor
   *
   * @param dataProvider
   * @param ic
   */
  private FragmentRootNode(IDataProvider dataProvid, Doc document, InstanceContent ic) {
    super(Children.create(new FragmentNodeChildFactory(dataProvid, document), true), new AbstractLookup(ic));

    this.dataProvider = dataProvid;
    this.instanceContent = ic;
    this.doc = document;

    fragmentType = new FragmentNewType(dataProvid, this, doc, true);
    instanceContent.add(fragmentType);

    CentralLookup centralLookup = CentralLookup.getDefault();

    // Add a new ability for this node to be reloaded
    /*
     * IRefreshableFragmentViewCapability
     */ rvc = new IRefreshableFragmentViewCapability() {

      @Override
      public void refreshChildren() throws Exception {
        // To reload this node just set a new set of children
        // using a FragmentNodeChildFactory object, that retrieves
        // children asynchronously
        CentralLookup cl = CentralLookup.getDefault();
        for (Node node : FragmentRootNode.this.getChildren().getNodes()) {
          FragmentNode frn = (FragmentNode) node;
          cl.remove(frn.getRVC());
        }
        setChildren(Children.create(new FragmentNodeChildFactory(FragmentRootNode.this.dataProvider, doc), true));
      }

      @Override
      public void refreshAfterDelete(Fragment frag) throws Exception {
        CentralLookup cl = CentralLookup.getDefault();
        for (Node node : FragmentRootNode.this.getChildren().getNodes()) {
          FragmentNode frn = (FragmentNode) node;
          cl.remove(frn.getRVC());
        }
        setChildren(Children.create(new FragmentNodeChildFactory(FragmentRootNode.this.dataProvider, doc), true));

      }

      @Override
      public void refreshAfterNew(Fragment frag) throws Exception {

        CentralLookup cl = CentralLookup.getDefault();
        for (Node node : FragmentRootNode.this.getChildren().getNodes()) {
          try {
            FragmentNode frn = (FragmentNode) node;
            cl.remove(frn.getRVC());
          } catch (Exception ex) {
            //todo
          }
        }
        setChildren(Children.create(new FragmentNodeChildFactory(FragmentRootNode.this.dataProvider, doc), true));
      }

      @Override
      public void refreshAfterEdit(Fragment frag) throws Exception {
        //TODO jedině pro editaci samotného díla, jinak asi nemá smysl
      }

      @Override
      public boolean canRefresh() {
        return true;
      }
    };
    this.instanceContent.add(rvc);
    centralLookup.add(rvc);
  }

  @Override
  public String getHtmlDisplayName() {
    if (doc.getTitle() == null || doc.getTitle().isEmpty()) {
      return "(" + doc.getAbbrev() + ") <i>" + doc.getWorkName() + "</i>";
    } else {
      return "(" + doc.getAbbrev() + ")" + doc.getTitle() + " <i>(" + doc.getWorkName() + ")</i>";
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public Action[] getActions(boolean context) {
    List<Action> fragmentActions = (List<Action>) Utilities.actionsForPath("Actions/RootNode");

    fragmentActions.add(PasteAction.get(PasteAction.class));
    fragmentActions.add(ReorderAction.get(ReorderAction.class));

    return fragmentActions.toArray(new Action[fragmentActions.size()]);
  }

  /**
   * Without this method, the NewAction does nothing on the root node.
   *
   * @return FragmentNewType instance, which is called by action NewAction
   * (registered in layer.xml)
   */
  @Override
  public NewType[] getNewTypes() {
    return new NewType[]{fragmentType};
  }

  @Override
  public PasteType getDropType(final Transferable t, int arg1, int arg2) {
    if (t.isDataFlavorSupported(FragmentFlavor.CHAPTER_FLAVOR)) {
      return new PasteType() {

        @Override
        public Transferable paste() throws IOException {
          try {
            /*
             * ICreatableFragmentEntityCapability cec =
             * dataProvider.getLookup().lookup(ICreatableFragmentEntityCapability.class);
             * cec.create((Fragment)
             * t.getTransferData(FragmentFlavor.CHAPTER_FLAVOR));
             */

            final Node node = NodeTransfer.node(t, NodeTransfer.DND_MOVE + NodeTransfer.CLIPBOARD_CUT);
            if (node != null) {
              node.destroy();
            }
            //} catch (UnsupportedFlavorException ex) {
            // logger.log(Level.WARNING, null, ex); //TODO provide a message from Bundle
          } catch (Exception e) {
            logger.log(Level.WARNING, null, e); //TODO provide a message from Bundle
          }
          return null;
        }
      };
    } else {
      return null;
    }
  }

  @Override
  protected void createPasteTypes(Transferable t, List<PasteType> s) {
    super.createPasteTypes(t, s);
    PasteType p = getDropType(t, 0, 0);
    if (p != null) {
      s.add(p);
    }
  }
}
